from flask import Blueprint, request, jsonify
from werkzeug.exceptions import BadRequest
from app import db
from sqlalchemy import func
from datetime import date
from app.recipes.models import Recipe, RecipeStep, RecipeIngredient, RecipeTag
from app.recipes.schemas import recipe_schema, recipes_schema, recipe_simple_schema, recipes_simple_schema
from app.ingredients.models import Ingredient
from app.tags.models import Tag
from app.categories.models import Category
from app.auth.routes import token_required
from flask import request, jsonify
from sqlalchemy.exc import IntegrityError

# 创建食谱模块的蓝图
recipes_bp = Blueprint('recipes', __name__)

@recipes_bp.route('', methods=['GET'])
def get_recipes():
    """
    获取所有食谱列表
    ---
    响应：食谱列表
    """
    recipes = Recipe.query.all()
    return jsonify(recipes_simple_schema.dump(recipes))

@recipes_bp.route('/<int:recipe_id>', methods=['GET'])
def get_recipe(recipe_id):
    """
    获取单个食谱的详细信息
    ---
    参数：recipe_id - 食谱ID
    响应：食谱详细信息（包含用户、分类、步骤、食材、标签等）
    """
    recipe = Recipe.query.get_or_404(recipe_id)
    return jsonify(recipe_schema.dump(recipe))

@recipes_bp.route('', methods=['POST'])
def create_recipe():
    """
    创建新食谱
    ---
    请求体：食谱信息
    响应：创建成功的食谱信息
    """
    data = request.get_json()
    
    if not data:
        raise BadRequest('No input data provided')
    
    # 验证必填字段
    required_fields = ['title', 'user_id', 'category_id', 'difficulty', 'cook_time']
    for field in required_fields:
        if field not in data:
            raise BadRequest(f'Missing required field: {field}')
    
    # 创建食谱对象
    recipe = Recipe(
        title=data['title'],
        description=data.get('description'),
        user_id=data['user_id'],
        category_id=data['category_id'],
        difficulty=data['difficulty'],
        cook_time=data['cook_time'],
        servings=data.get('servings'),
        cover_image=data.get('cover_image')
    )
    
    try:
        db.session.add(recipe)
        db.session.commit()
        
        # 处理步骤
        if 'steps' in data:
            for i, step_data in enumerate(data['steps']):
                step = RecipeStep(
                    recipe_id=recipe.id,
                    step_number=step_data.get('step_number', i+1),
                    description=step_data['description'],
                    image_url=step_data.get('image_url')
                )
                db.session.add(step)
        
        # 处理食材
        if 'ingredients' in data:
            for ingredient_data in data['ingredients']:
                # 如果ingredient_id为None或空，尝试根据名称查找或创建新食材
                ingredient = None
                if ingredient_data.get('ingredient_id'):
                    ingredient = Ingredient.query.get(ingredient_data['ingredient_id'])
                
                # 如果没有找到食材ID对应的食材，或者ingredient_id为None，
                # 检查是否提供了食材名称，如果有则创建新食材
                if not ingredient and ingredient_data.get('name'):
                    # 检查是否已存在同名食材
                    existing_ingredient = Ingredient.query.filter_by(name=ingredient_data['name']).first()
                    if existing_ingredient:
                        ingredient = existing_ingredient
                    else:
                        # 创建新食材
                        ingredient = Ingredient(
                            name=ingredient_data['name'],
                            category=ingredient_data.get('category_id')
                        )
                        db.session.add(ingredient)
                        db.session.flush()  # 获取新食材的ID
                
                if ingredient:
                    recipe_ingredient = RecipeIngredient(
                        recipe_id=recipe.id,
                        ingredient_id=ingredient.id,
                        quantity=ingredient_data.get('quantity'),
                        unit=ingredient_data.get('unit')
                    )
                    db.session.add(recipe_ingredient)
        
        # 处理标签
        if 'tags' in data:
            for tag_data in data['tags']:
                # 检查标签是否存在
                tag = Tag.query.get(tag_data['tag_id'])
                if not tag:
                    raise BadRequest(f'Tag not found: {tag_data["tag_id"]}')
                
                recipe_tag = RecipeTag(
                    recipe_id=recipe.id,
                    tag_id=tag_data['tag_id']
                )
                db.session.add(recipe_tag)
        
        db.session.commit()
        
        return jsonify(recipe_schema.dump(recipe)), 201
    except IntegrityError as e:
        db.session.rollback()
        # 检查是否是唯一性约束违反
        if 'UNIQUE constraint failed: recipes.user_id, recipes.title' in str(e):
            raise BadRequest('您已经创建了同名的菜谱')
        raise BadRequest(f'创建菜谱失败: {str(e)}')
    except Exception as e:
        db.session.rollback()
        raise BadRequest(f'创建菜谱失败: {str(e)}')

@recipes_bp.route('/<int:recipe_id>', methods=['PUT'])
def update_recipe(recipe_id):
    """
    更新食谱信息
    ---
    参数：recipe_id - 食谱ID
    请求体：更新的食谱信息
    响应：更新后的食谱信息
    """
    recipe = Recipe.query.get_or_404(recipe_id)
    data = request.get_json()
    
    if not data:
        raise BadRequest('No input data provided')
    
    # 更新基本信息
    if 'title' in data: recipe.title = data['title']
    if 'description' in data: recipe.description = data['description']
    if 'user_id' in data: recipe.user_id = data['user_id']
    if 'category_id' in data: recipe.category_id = data['category_id']
    if 'difficulty' in data: recipe.difficulty = data['difficulty']
    if 'cook_time' in data: recipe.cook_time = data['cook_time']
    if 'servings' in data: recipe.servings = data['servings']
    if 'cover_image' in data: recipe.cover_image = data['cover_image']
    
    # 处理步骤更新
    if 'steps' in data:
        # 删除现有步骤
        RecipeStep.query.filter_by(recipe_id=recipe_id).delete()
        # 添加新步骤
        for i, step_data in enumerate(data['steps']):
            step = RecipeStep(
                recipe_id=recipe.id,
                step_number=step_data.get('step_number', i+1),
                description=step_data['description'],
                image_url=step_data.get('image_url')
            )
            db.session.add(step)
    
    # 处理食材更新
    if 'ingredients' in data:
        # 删除现有食材关联
        RecipeIngredient.query.filter_by(recipe_id=recipe_id).delete()
        # 添加新食材关联
        for ingredient_data in data['ingredients']:
            # 如果ingredient_id为None或空，尝试根据名称查找或创建新食材
            ingredient = None
            if ingredient_data.get('ingredient_id'):
                ingredient = Ingredient.query.get(ingredient_data['ingredient_id'])
            
            # 如果没有找到食材ID对应的食材，或者ingredient_id为None，
            # 检查是否提供了食材名称，如果有则创建新食材
            if not ingredient and ingredient_data.get('name'):
                # 检查是否已存在同名食材
                existing_ingredient = Ingredient.query.filter_by(name=ingredient_data['name']).first()
                if existing_ingredient:
                    ingredient = existing_ingredient
                else:
                    # 创建新食材
                    ingredient = Ingredient(
                        name=ingredient_data['name'],
                        category_id=ingredient_data.get('category_id')
                    )
                    db.session.add(ingredient)
                    db.session.flush()  # 获取新食材的ID
            
            if ingredient:
                recipe_ingredient = RecipeIngredient(
                    recipe_id=recipe.id,
                    ingredient_id=ingredient.id,
                    quantity=ingredient_data.get('quantity'),
                    unit=ingredient_data.get('unit')
                )
                db.session.add(recipe_ingredient)
    
    # 处理标签更新
    if 'tags' in data:
        # 删除现有标签关联
        RecipeTag.query.filter_by(recipe_id=recipe_id).delete()
        # 添加新标签关联
        for tag_data in data['tags']:
            # 检查标签是否存在
            tag = Tag.query.get(tag_data['tag_id'])
            if not tag:
                raise BadRequest(f'Tag not found: {tag_data["tag_id"]}')
            
            recipe_tag = RecipeTag(
                recipe_id=recipe.id,
                tag_id=tag_data['tag_id']
            )
            db.session.add(recipe_tag)
    
    db.session.commit()
    
    return jsonify(recipe_schema.dump(recipe))

@recipes_bp.route('/<int:recipe_id>', methods=['DELETE'])
def delete_recipe(recipe_id):
    """
    删除食谱
    ---
    参数：recipe_id - 食谱ID
    响应：成功删除的消息
    """
    recipe = Recipe.query.get_or_404(recipe_id)
    
    # 级联删除相关数据
    RecipeStep.query.filter_by(recipe_id=recipe_id).delete()
    RecipeIngredient.query.filter_by(recipe_id=recipe_id).delete()
    RecipeTag.query.filter_by(recipe_id=recipe_id).delete()
    
    db.session.delete(recipe)
    db.session.commit()
    
    return jsonify({'message': 'Recipe deleted successfully'})

@recipes_bp.route('/category/<int:category_id>', methods=['GET'])
def get_recipes_by_category(category_id):
    """
    根据分类获取食谱
    ---
    参数：category_id - 分类ID
    响应：食谱列表
    """
    recipes = Recipe.query.filter_by(category_id=category_id).all()
    return jsonify(recipes_simple_schema.dump(recipes))

@recipes_bp.route('/search', methods=['GET'])
def search_recipes():
    """
    搜索食谱
    ---
    参数：q - 搜索关键词
    响应：匹配的食谱列表
    """
    keyword = request.args.get('q', '')
    if not keyword:
        return jsonify(recipes_simple_schema.dump([]))
    
    recipes = Recipe.query.filter(
        Recipe.title.contains(keyword) | Recipe.description.contains(keyword)
    ).all()
    
    return jsonify(recipes_simple_schema.dump(recipes))

@recipes_bp.route('/category/name/<string:category_name>', methods=['GET'])
def get_recipes_by_category_name(category_name):
    """
    根据分类名称获取食谱（包括该分类及其所有子分类下的食谱）
    ---
    参数：category_name - 分类名称
    响应：食谱列表
    """
    # 查找指定名称的分类
    category = Category.query.filter_by(name=category_name).first()
    if not category:
        return jsonify(recipes_simple_schema.dump([]))
    
    # 获取该分类及其所有子分类的ID
    category_ids = [category.id]
    
    def get_all_child_ids(parent_id):
        children = Category.query.filter_by(parent_id=parent_id).all()
        for child in children:
            category_ids.append(child.id)
            get_all_child_ids(child.id)  # 递归获取所有子分类的ID
    
    get_all_child_ids(category.id)
    
    # 查询所有属于这些分类的食谱
    recipes = Recipe.query.filter(Recipe.category_id.in_(category_ids)).all()
    
    # 序列化食谱数据
    serialized_recipes = recipes_simple_schema.dump(recipes)
    
    # 确保所有食谱显示请求的分类名称
    for recipe in serialized_recipes:
        # 覆盖原始分类信息，确保显示请求的分类名称
        recipe['category'] = {
            'id': category.id,
            'name': category_name,
            'description': category.description,
            'children': []  # 清空子分类以避免混淆
        }
    
    return jsonify(serialized_recipes)

@recipes_bp.route('/random', methods=['GET'])
def get_random_recipe():
    """
    获取单个随机食谱的详细信息
    ---
    响应：随机食谱的详细信息
    """
    recipe = Recipe.query.order_by(func.random()).first()
    if not recipe:
        return jsonify({'message': 'No recipes found'}), 404
    return jsonify(recipe_schema.dump(recipe))

@recipes_bp.route('/random/three', methods=['GET'])
def get_three_random_recipes():
    """
    获取三个随机食谱的信息
    ---
    响应：三个随机食谱的列表
    """
    recipes = Recipe.query.order_by(func.random()).limit(3).all()
    return jsonify(recipes_simple_schema.dump(recipes))


@recipes_bp.route('/daily-featured', methods=['GET'])
def get_daily_featured_recipe():
    """
    获取今日固定的精选食谱
    ---
    参数：seed - 可选，测试用的日期种子（格式：YYYYMMDD）
    响应：当日固定的精选食谱详细信息
    """
    # 获取查询参数中的种子，如果没有则使用当前日期
    seed_param = request.args.get('seed')
    
    if seed_param:
        # 使用提供的种子进行测试
        try:
            seed = int(seed_param)
        except ValueError:
            return jsonify({'message': 'Invalid seed format, use YYYYMMDD'}), 400
    else:
        # 使用当前日期作为种子
        from datetime import date
        today = date.today()
        seed = today.year * 10000 + today.month * 100 + today.day
    
    # 计算随机偏移量
    # 这种方法适用于大多数数据库，不需要特定的设置种子语法
    offset = seed % Recipe.query.count() if Recipe.query.count() > 0 else 0
    
    # 使用偏移量获取固定的随机食谱
    recipe = Recipe.query.offset(offset).first()
    
    if not recipe:
        return jsonify({'message': 'No recipes found'}), 404
    
    return jsonify(recipe_schema.dump(recipe))


@recipes_bp.route('/daily-meals', methods=['GET'])
def get_daily_meals():
    """
    获取今日固定的三餐食谱
    ---
    响应：当日固定的三餐食谱列表（含餐别类型）
    # 测试示例
    GET /api/recipes/daily-meals?seed=20231226
    """
    # 获取查询参数中的种子，如果没有则使用当前日期
    seed_param = request.args.get('seed')
    
    if seed_param:
        # 使用提供的种子进行测试
        try:
            seed = int(seed_param)
        except ValueError:
            return jsonify({'message': 'Invalid seed format, use YYYYMMDD'}), 400
    else:
        # 使用当前日期作为种子
        today = date.today()
        seed = today.year * 10000 + today.month * 100 + today.day
    
    total_recipes = Recipe.query.count()
    
    if total_recipes == 0:
        return jsonify([])
    
    # 使用种子生成固定的随机结果，但确保返回三个不同的食谱
    recipes = []
    
    # 设置一个固定的随机状态，基于日期种子
    import random
    random.seed(seed)
    
    # 获取所有食谱的ID列表
    all_recipe_ids = [recipe.id for recipe in Recipe.query.with_entities(Recipe.id).all()]
    
    if len(all_recipe_ids) >= 3:
        # 如果食谱数量足够，随机选择3个不同的ID
        selected_ids = random.sample(all_recipe_ids, 3)
    else:
        # 如果食谱数量不足3个，则循环使用现有食谱
        selected_ids = all_recipe_ids.copy()
        while len(selected_ids) < 3:
            selected_ids.extend(all_recipe_ids)
        selected_ids = selected_ids[:3]
    
    # 根据选中的ID获取完整的食谱对象
    for recipe_id in selected_ids:
        recipe = Recipe.query.get(recipe_id)
        if recipe:
            recipes.append(recipe)
    
    # 为每个食谱添加餐别类型
    meal_types = ['早餐', '午餐', '晚餐']
    result = []
    for i, recipe in enumerate(recipes):
        # 使用正确的schema来序列化单个食谱对象
        recipe_data = recipe_simple_schema.dump(recipe)
        recipe_data['type'] = meal_types[i % len(meal_types)]
        result.append(recipe_data)
    
    return jsonify(result)

@recipes_bp.route('/user/recipes', methods=['GET'])
@token_required
def get_user_recipes(current_user):
    """
    获取当前用户创建的所有食谱
    ---
    响应：当前用户创建的食谱列表
    """
    # 根据当前用户ID查询食谱
    recipes = Recipe.query.filter_by(user_id=current_user.id).all()
    return jsonify(recipes_simple_schema.dump(recipes))